package com.gitee.taotaojs.util.date;

import com.gitee.taotaojs.util.ConstantUtil;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

/**
 * 日历工具类
 * @author TaoTaojs
 * @date 2019年11月19日10:55:04
 * <p>Description</p>
 *  - 创建日历实例
 *  - 快速日期格式化方法
 *  - 获取前后某个单位时间的日期
 * 关联类:
 * 参考链接：
 */
public class CalendarUtil {

	/** "yyyy-MM-dd" */
	public static final String FORMAT_DATE = "yyyy-MM-dd";
	/** "HH:mm:ss" */
	public static final String FORMAT_TIME = "HH:mm:ss";
	/** "yyyy-MM-dd HH:mm:ss" */
	public static final String FORMAT_ALL = "yyyy-MM-dd HH:mm:ss";
	/** "yyyy年MM月dd日HH时mm分ss秒" */
	public static final String FORMAT_CHINA_ALL = "yyyy年MM月dd日HH时mm分ss秒";

	/** 周几为一周开始 */
	public static final Integer WEEK_START = 1;

	/**
	 * 判断Calendar是否需要初始化日期，并创建返回
	 * @param date 指定时间
	 * @return 判空之后返回日历对象，如果为空则返回现在
	 */
	public static Calendar getCalendar(Date date){
		Calendar calendar = null;
		if(date != null){
			calendar = Calendar.getInstance();
			calendar.setTime(date);
		} else {
			calendar = Calendar.getInstance();
		}
		return calendar;
	}



	public static void main(String[] args) {
		System.out.println(formatDate(getCalendar(null, 2021, 2, 2,3,null), FORMAT_ALL));
		Calendar c = getCalendar(null);
		c.set(Calendar.WEEK_OF_YEAR, 3);
		c.set(Calendar.DAY_OF_WEEK,1);
		System.out.println(formatDate(c.getTime(), FORMAT_ALL));
	}

	/**
	 * 根据年月周日生成对应的日历对象，可填null
	 * @param date 锚定时间
	 * @param year 年
	 * @param quarter 季
	 * @param month 月
	 * @param week 周
	 * @param day 日
	 * @return 时间
	 */
	public static Date getCalendar(Date date, Integer year, Integer quarter, Integer month, Integer week, Integer day){
		Calendar a = null;
		if(date != null){
			date = new Date(0);
		}

		a = getCalendar(date);

		//注入年度
		if(year != null){
			a.set(Calendar.YEAR, year);
		}

		if(quarter != null){
			quarter = (quarter-1) * 3;
			a.set(Calendar.MONTH, quarter);

			if(month != null){
				//季月
				a.set(Calendar.MONTH, quarter + month-1);
				if(week != null){
					//季月周
					a.set(Calendar.WEEK_OF_MONTH, week);
					if(day != null) {
						//季月周日
						a.set(Calendar.DAY_OF_WEEK, checkWeekDay(day));
					} else {
						//季月周0
						a.set(Calendar.DAY_OF_WEEK, checkWeekDay(1));
					}
				} else {
					//季月0
					if(day != null) {
						//季月天
						a.set(Calendar.DAY_OF_MONTH, day);
					}
				}
			} else {
				//季无
				if(week != null){
					//季周
					a.set(Calendar.WEEK_OF_MONTH, week);
					if(day != null) {
						//季周天
						a.set(Calendar.DAY_OF_WEEK, checkWeekDay(day));
					} else {
						//季周0
						a.set(Calendar.DAY_OF_WEEK, checkWeekDay(1));
					}
				} else {
					//季无
					if(day != null) {
						//季天
						a.set(Calendar.DAY_OF_MONTH, day);
					}
				}
			}
		} else {
			//0
			if(month != null){
				//月
				a.set(Calendar.MONTH, month-1);
				if(week != null){
					//月周
					a.set(Calendar.WEEK_OF_MONTH, week);
					if(day != null) {
						//月周天
						a.set(Calendar.DAY_OF_WEEK, checkWeekDay(day));
					} else {
						//月周0
						a.set(Calendar.DAY_OF_WEEK, checkWeekDay(1));
					}
				} else {
					//月0
					if(day != null) {
						//月天
						a.set(Calendar.DAY_OF_MONTH, day);
					}
				}
			} else {
				//0
				if(week != null){
					//周
					a.set(Calendar.WEEK_OF_YEAR, week);
					if(day != null) {
						//周天
						a.set(Calendar.DAY_OF_WEEK, checkWeekDay(day));
					} else {
						//周0
						a.set(Calendar.DAY_OF_WEEK, checkWeekDay(1));
					}
				} else {
					//0
					if(day != null) {
						//天
						a.set(Calendar.DAY_OF_YEAR, day);
					}
				}
			}
		}

		return a.getTime();
	}

	/**
	 * 检查周数据是否正常
	 * @param weekDay 周几
	 * @return 正确的周数据
	 */
	private static int checkWeekDay(Integer weekDay){
		weekDay = weekDay + WEEK_START;
		return weekDay % 7;
	}

	/**
	 * 设置时间
	 * @param date
	 * @param hour
	 * @param minute
	 * @param second
	 * @param milliseconds
	 * @return
	 */
	public static Calendar setCalendarTime(Date date, Integer hour, Integer minute, Integer second, Integer milliseconds){
		Calendar a = null;
		if(date != null){
			a = getCalendar(date);
		} else {
			a = Calendar.getInstance();
		}

		if(hour != null){
			a.set(Calendar.HOUR_OF_DAY, hour);
		}
		if(minute != null){
			a.set(Calendar.MINUTE, minute);
		}
		if(second != null){
			a.set(Calendar.SECOND, second);
		}
		if(milliseconds != null){
			a.set(Calendar.MILLISECOND, milliseconds);
		}
		return a;
	}

	/**
	 * 根据年月周日生成对应的日历对象，可填null
	 * @param date 锚定时间
	 * @param year 年
	 * @param quarter 季
	 * @param month 月
	 * @param week 周
	 * @param day 日
	 * @return 时间
	 */
	public static Date addCalendar(Date date, Integer year, Integer quarter, Integer month, Integer week, Integer day){
		Calendar a = null;
		if(date != null){
			date = new Date(0);
		}

		a = getCalendar(date);

		//注入年度
		if(year != null){
			a.add(Calendar.YEAR, year);
		}

		if(quarter != null){
			a.add(Calendar.MONTH, quarter * 3);

			if(month != null){
				//季月
				a.add(Calendar.MONTH,  month);
				if(week != null){
					//季月周
					a.add(Calendar.WEEK_OF_MONTH, week);
					if(day != null) {
						//季月周日
						a.add(Calendar.DAY_OF_WEEK, day);
					}
				} else {
					//季月0
					if(day != null) {
						//季月天
						a.add(Calendar.DAY_OF_MONTH, day);
					}
				}
			} else {
				//季无
				if(week != null){
					//季周
					a.add(Calendar.WEEK_OF_MONTH, week);
					if(day != null) {
						//季周天
						a.add(Calendar.DAY_OF_WEEK, day);
					}
				} else {
					//季无
					if(day != null) {
						//季天
						a.add(Calendar.DAY_OF_MONTH, day);
					}
				}
			}
		} else {
			//0
			if(month != null){
				//月
				a.add(Calendar.MONTH, month);
				if(week != null){
					//月周
					a.add(Calendar.WEEK_OF_MONTH, week);
					if(day != null) {
						//月周天
						a.add(Calendar.DAY_OF_WEEK, day);
					}
				} else {
					//月0
					if(day != null) {
						//月天
						a.add(Calendar.DAY_OF_MONTH, day);
					}
				}
			} else {
				//0
				if(week != null){
					//周
					a.add(Calendar.WEEK_OF_YEAR, week);
					if(day != null) {
						//周天
						a.add(Calendar.DAY_OF_WEEK, day);
					}
				} else {
					//0
					if(day != null) {
						//天
						a.add(Calendar.DAY_OF_YEAR, day);
					}
				}
			}
		}

		return a.getTime();
	}

	/**
	 * 根据对应的时间传参来对指定时间进行增删操作（未完善）
	 * @param date
	 * @param hour
	 * @param minute
	 * @param second
	 * @param milliseconds
	 * @return
	 */
	public static Calendar addCalendarTime(Date date, Integer hour, Integer minute, Integer second, Integer milliseconds){
		Calendar a = getCalendar(date);
		if(hour != null){
			a.add(Calendar.HOUR_OF_DAY, hour);
		}
		if(minute != null){
			a.add(Calendar.MINUTE, minute);
			if(second != null){
				a.add(Calendar.SECOND, second);
				if(milliseconds != null){
					a.add(Calendar.MILLISECOND, milliseconds);
				} else {
					a.set(Calendar.MILLISECOND, a.getActualMinimum(Calendar.MILLISECOND));
				}
			} else {
				if(milliseconds != null){
					a.add(Calendar.MILLISECOND, milliseconds);
				} else {
					a.set(Calendar.MILLISECOND, a.getActualMinimum(Calendar.MILLISECOND));
				}
				a.set(Calendar.SECOND, a.getActualMinimum(Calendar.SECOND));
				a.set(Calendar.MILLISECOND, a.getActualMinimum(Calendar.MILLISECOND));
			}
		} else {
			if(second != null){
				a.add(Calendar.SECOND, second);
				if(milliseconds != null){
					a.add(Calendar.MILLISECOND, milliseconds);
				} else {
					a.set(Calendar.MINUTE, a.getActualMinimum(Calendar.MINUTE));
					a.set(Calendar.MILLISECOND, a.getActualMinimum(Calendar.MILLISECOND));
				}
			} else {
				a.set(Calendar.MINUTE, a.getActualMinimum(Calendar.MINUTE));
				a.set(Calendar.SECOND, a.getActualMinimum(Calendar.SECOND));
				a.set(Calendar.MILLISECOND, a.getActualMinimum(Calendar.MILLISECOND));
			}

		}
		if(second != null){
			a.add(Calendar.SECOND, second);
		} else {
			a.set(Calendar.SECOND, a.getActualMinimum(Calendar.SECOND));
		}
		if(milliseconds != null){
			a.add(Calendar.MILLISECOND, milliseconds);
		} else {
			a.set(Calendar.MILLISECOND, a.getActualMinimum(Calendar.MILLISECOND));
		}

		return a;
	}

	/**
	 * 获取某年第几季度的日期
	 * @param year
	 * @param quarter
	 * @return
	 */
	public static Calendar getCalendarByQuarter(Integer year, Integer quarter){
		Calendar a = Calendar.getInstance();
		a.set(Calendar.YEAR, year);
		a.set(Calendar.MONTH, quarter * 3);
		a.set(Calendar.DAY_OF_MONTH, 1);
		return a;
	}

	/**
	 * 获取某年上半年或下半年的日期
	 * @param year
	 * @param halfYear
	 * @return
	 */
	public static Calendar getCalendarByHalfYear(Integer year, Integer halfYear){
		Calendar a = Calendar.getInstance();
		a.set(Calendar.YEAR, year);
		a.set(Calendar.MONTH, halfYear * 6);
		a.set(Calendar.DAY_OF_MONTH, 1);
		return a;
	}

	/**
	 * 前几天或者后几天的日期
	 * @param date 指定时间
	 * @param i 数字0表示为当天23:59:59   1表示明天   -1表示昨天
	 * @return 前几天或者后几天的日期
	 */
	public static Date getLastOrNextDate(Date date, final int i){
		Calendar calendar = CalendarUtil.getCalendar(date);
		calendar.add(Calendar.DAY_OF_YEAR, i);
		calendar.set(Calendar.HOUR_OF_DAY, calendar.getActualMinimum(Calendar.HOUR_OF_DAY));
		calendar.set(Calendar.MINUTE, calendar.getActualMinimum(Calendar.MINUTE));
		calendar.set(Calendar.SECOND, calendar.getActualMinimum(Calendar.SECOND));
		//如果是后几天，那么秒数减一
		if(i >= 0){
			calendar.add(Calendar.DAY_OF_YEAR, 1);
			calendar.add(Calendar.SECOND, -1);
		}
		return calendar.getTime();
	}

	/**
	 * 前几小时或者后几小时的日期
	 * @param date 指定时间
	 * @param i 数字0表示为当前小时
	 * @return 前几小时或者后几小时的日期
	 */
	public static Date getLastOrNextHour(Date date, final int i){
		Calendar calendar = CalendarUtil.getCalendar(date);
		calendar.add(Calendar.HOUR_OF_DAY, i);
		calendar.set(Calendar.MINUTE, calendar.getActualMinimum(Calendar.MINUTE));
		calendar.set(Calendar.SECOND, calendar.getActualMinimum(Calendar.SECOND));
		return calendar.getTime();
	}

	/**
	 * 快速格式化日期方法
	 * @param date 指定时间
	 * @param formatStr 格式化样式
	 * @return 时间字符串
	 */
	public static String formatDate(Date date, String formatStr){
		SimpleDateFormat dateFormat = new SimpleDateFormat(formatStr);
		return dateFormat.format(date);
	}

	/**
	 * 获取当前日期
	 * @param stringType 指定日期字符串
	 * @return 获取当前日期
	 */
	public String getNow(String stringType) {
		Calendar calendar = Calendar.getInstance();
		return new SimpleDateFormat(stringType).format(calendar.getTime());
	}

	/**
	 * 获取前/后几天的日期
	 * @param i 日期坐标
	 * @param stringType 指定日期字符串
	 * @return 获取前/后几天的日期
	 */
	public String getLastOrNextDate(int i, String stringType) {
		Calendar calendar = Calendar.getInstance();
		calendar.add(Calendar.DAY_OF_YEAR, i);
		return new SimpleDateFormat(stringType).format(calendar.getTime());
	}

	/**
	 * 获取这周某天日期
	 * @param i 日期坐标
	 * @param stringType 指定日期字符串
	 * @return 获取这周某天日期
	 */
	public String getOneDateOfWeek(int i, String stringType) {
		Calendar calendar = Calendar.getInstance();

		if (calendar.get(Calendar.DAY_OF_WEEK) != 1) {
			if (i <= ConstantUtil.SIX) {
				calendar.set(Calendar.DAY_OF_WEEK, i + 1);
			} else if (i == ConstantUtil.SEVEN) {
				calendar.add(Calendar.WEEK_OF_MONTH, 1);
				calendar.set(Calendar.DAY_OF_WEEK, 1);
			}
		} else {
			if (i <= ConstantUtil.SIX) {
				calendar.add(Calendar.WEEK_OF_MONTH, -1);
				calendar.set(Calendar.DAY_OF_WEEK, i + 1);
			} else if (i == ConstantUtil.SEVEN) {
				calendar.set(Calendar.DAY_OF_WEEK, 1);
			}
		}
		return new SimpleDateFormat(stringType).format(calendar.getTime());
	}

	/**
	 * 获取前/后第几周日期
	 * @param i 日期坐标
	 * @param stringType 指定日期字符串
	 * @return 获取前/后第几周日期
	 */
	public String getLastOrNextWeek(int i, String stringType) {
		Calendar calendar = Calendar.getInstance();
		calendar.add(Calendar.WEEK_OF_MONTH, i);
		return new SimpleDateFormat(stringType).format(calendar.getTime());
	}

	/**
	 * 获取前/后几个月对应日期
	 * @param i 日期坐标
	 * @param stringType 指定日期字符串
	 * @return 获取前/后几个月对应日期
	 */
	public String getlastOrNextDateOfMonth(int i, String stringType) {
		Calendar calendar = Calendar.getInstance();
		calendar.add(Calendar.MONTH, i);
		return new SimpleDateFormat(stringType).format(calendar.getTime());
	}

	/**
	 * 获取某月某一天日期
	 * @param month 月
	 * @param day 日
	 * @param stringType 返回的字符串格式
	 * @return 字符串
	 */
	public String getOneDateOfMonth(int month, int day, String stringType) {
		Calendar calendar = Calendar.getInstance();
		calendar.add(Calendar.MONTH, month);
		calendar.set(Calendar.DAY_OF_MONTH, day);
		return new SimpleDateFormat(stringType).format(calendar.getTime());
	}

	/**
	 * 获取某月第一天日期
	 * @param month 月
	 * @param stringType 返回的字符串格式
	 * @return 字符串
	 */
	public String getFirstDateOfMonth(int month, String stringType) {
		Calendar calendar = Calendar.getInstance();
		calendar.add(Calendar.MONTH, month);
		calendar.set(Calendar.DAY_OF_MONTH, 1);
		return new SimpleDateFormat(stringType).format(calendar.getTime());
	}

	/**
	 * 获取某月最后一天日期
	 * @param month 月
	 * @param stringType 返回的字符串格式
	 * @return 字符串
	 */
	public String getLastDateOfMonth(int month, String stringType) {
		Calendar calendar = Calendar.getInstance();
		calendar.add(Calendar.MONTH, month + 1);
		calendar.set(Calendar.DAY_OF_MONTH, 0);
		return new SimpleDateFormat(stringType).format(calendar.getTime());
	}

	/**
	 * 获取某月第一天零点日期时间
	 * @param month 月
	 * @param stringType 返回字符串格式
	 * @return 字符串
	 * @throws ParseException 格式转换异常
	 */
	public Date getFirstDateTimeZoreOfMonth(int month, String stringType) throws ParseException {
		Calendar calendar = Calendar.getInstance();
		calendar.add(Calendar.MONTH, month);
		calendar.set(Calendar.DAY_OF_MONTH, 1);
		return new SimpleDateFormat(stringType).parse(new SimpleDateFormat(stringType).format(calendar.getTime()));
	}

	/**
	 * 获取前/后几年的日期
	 * @param year 年
	 * @param stringType 返回字符串格式
	 * @return 字符串
	 */
	public String getlastOrNextDateOfYear(int year, String stringType) {
		Calendar calendar = Calendar.getInstance();
		calendar.add(Calendar.YEAR, year);
		return new SimpleDateFormat(stringType).format(calendar.getTime());
	}

	/**
	 * 获取某年第几天的日期
	 * @param year 年
	 * @param day 天
	 * @param stringType 返回字符串格式
	 * @return 字符串
	 */
	public String getOneDateOfYear(int year, int day, String stringType) {
		Calendar calendar = Calendar.getInstance();
		calendar.add(Calendar.YEAR, year);
		calendar.set(Calendar.DAY_OF_YEAR, day);
		return new SimpleDateFormat(stringType).format(calendar.getTime());
	}

	/**
	 * 获取两个时间的月份差
	 * @param startData 开始时间
	 * @param stopData 结束时间
	 * @return 结束时间-开始时间 = 正数，开始时间小于结束时间，，负数，开始时间大于结束时间
	 */
	public static int getDifferMonth(Date startData, Date stopData){
		//固定的某个日期
		Calendar start  = Calendar.getInstance();
		//当前的日期
		Calendar stop = Calendar.getInstance();
		start.setTime(startData);
		stop.setTime(stopData);
		int result = (stop.get(Calendar.MONTH) - start.get(Calendar.MONTH));
		int month = (stop.get(Calendar.YEAR) - start .get(Calendar.YEAR))*12;
		return result + month;
	}

	/**
	 * 获取两个时间的月份差（已经绝对值了）
	 * @param afterData
	 * @param beforeData
	 * @return
	 */
	public static int getDifferMonthAbs(Date afterData, Date beforeData){
		return Math.abs(getDifferMonth(afterData, beforeData));
	}

	/**
	 * 查找本天是第几周，通常与本年最后一天使用，用于查询本年一共有几周
	 * @param date
	 * @return
	 */
	public static int getWeekOfYear(Date date) {
		Calendar c = new GregorianCalendar();
		c.setFirstDayOfWeek(Calendar.MONDAY);
		c.setMinimalDaysInFirstWeek(7);
		c.setTime(date);

		return c.get(Calendar.WEEK_OF_YEAR);
	}

	/**
	 * 获取某年的第一天
	 * @param year
	 * @return
	 */
	public static Date getYearFirst(int year){
		Calendar calendar = Calendar.getInstance();
		calendar.clear();
		calendar.set(Calendar.YEAR, year);
		calendar.roll(Calendar.DAY_OF_YEAR, -1);
		return calendar.getTime();
	}

	/**
	 * 获取某年的最后一天
	 * @param year
	 * @return
	 */
	public static Date getYearLast(int year){
		Calendar calendar = Calendar.getInstance();
		calendar.clear();
		calendar.set(Calendar.YEAR, year);
		calendar.roll(Calendar.DAY_OF_YEAR, -1);
		return calendar.getTime();
	}

	/**
	 * 获取某年总天数
	 * @param year
	 * @return
	 */
	public static int getYearSumDay(int year) {
		Calendar calendar = Calendar.getInstance();
		calendar.set(Calendar.YEAR, year);
		return calendar.getActualMaximum(Calendar.DAY_OF_YEAR);
	}

	/**
	 * 根据 年、月 获取对应的月份 的 天数
	 */
	public static int getMonthSumDay(int year, int month) {
		Calendar a = Calendar.getInstance();
		a.set(Calendar.YEAR, year);
		a.set(Calendar.MONTH, month - 1);
		a.set(Calendar.DATE, 1);
		a.roll(Calendar.DATE, -1);
		int maxDate = a.get(Calendar.DATE);
		return maxDate;
	}

	/**
	 * 获取当前年份
	 * @return
	 */
	public static Integer getYear(Date date){
		return getCalendar(date).get(Calendar.YEAR);
	}

	/**
	 * 获取月份
	 * @param date
	 * @return
	 */
	public static Integer getMonth(Date date){
		return getCalendar(date).get(Calendar.MONTH)+1;
	}

	/**
	 * 获取季度
	 * @param date
	 * @return
	 */
	public static Integer getSeason(Date date){
		return getMonth(date)/4 + 1;
	}

	/**
	 * 获取天数
	 * @param date
	 * @return
	 */
	public static Integer getDay(Date date){
		return getCalendar(date).get(Calendar.DAY_OF_YEAR);
	}

	/**
	 * 获取周
	 * @param date
	 * @return
	 */
	public static Integer getWeek(Date date){
		Calendar calendar = getCalendar(date);
		calendar.add(Calendar.DAY_OF_YEAR, -7);
		return calendar.get(Calendar.WEEK_OF_YEAR);
	}

	/**
	 * 获取半年
	 * @param date
	 * @return
	 */
	public static Integer getHalfYear(Date date){
		return getMonth(date)/6 + 1;
	}



}
